home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Internet / WWW / swish.11 / src / search.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  18KB  |  863 lines

  1. /*
  2. ** Copyright (C) 1995, Enterprise Integration Technologies Corp.        
  3. ** All Rights Reserved.
  4. ** Kevin Hughes, kevinh@eit.com 
  5. ** 3/11/94
  6. */
  7.  
  8. #include "swish.h"
  9. #include "search.h"
  10.  
  11. /* The main search function.
  12. ** Parentheses are stripped out, things made lowercase,
  13. ** extra blanks removed, etc.
  14. */
  15.  
  16. void search(words, indexlist, structure)
  17.      char *words;
  18.      struct swline *indexlist;
  19.      int structure;
  20. {
  21.         int i, j;
  22.         float num;
  23.         char word[MAXWORDLEN];
  24.     struct result *resultlist;
  25.     struct sortresult *sortresultlist;
  26.     struct swline *tmplist;
  27.         FILE *fp;
  28.  
  29.     searchwordlist = NULL;
  30.  
  31.         for (i = j = 0; words[i] != '\0' && words[i] != '\n'; i++) {
  32.         if (isspace(words[i]) || words[i] == '(' ||
  33.         words[i] == ')') {
  34.             if (j) {
  35.                 word[j] = '\0';
  36.                 searchwordlist = (struct swline *)
  37.                 addswline(searchwordlist, (char *)
  38.                 convertentities(word));
  39.                 j = 0;
  40.             }
  41.             if (words[i] == '(') {
  42.                 searchwordlist = (struct swline *)
  43.                 addswline(searchwordlist, "(");
  44.             }
  45.             if (words[i] == ')') {
  46.                 searchwordlist = (struct swline *)
  47.                 addswline(searchwordlist, ")");
  48.             }
  49.         }
  50.         else
  51.             word[j++] = tolower(words[i]);
  52.     }
  53.     if (j) {
  54.         word[j] = '\0';
  55.         searchwordlist = (struct swline *)
  56.         addswline(searchwordlist, (char *) convertentities(word));
  57.     }
  58.  
  59.         printf("%s\n", INDEXHEADER);
  60.         if (words[0] == '\0') {
  61.                 printf("err: no search words specified\n.\n");
  62.                 exit(0);
  63.         }
  64.  
  65.         printf("search words:");
  66.     tmplist = searchwordlist;
  67.     while (tmplist != NULL) {
  68.         printf(" %s", tmplist->line);
  69.         tmplist = tmplist->next;
  70.     }
  71.     putchar('\n');
  72.  
  73.     while (indexlist != NULL) {
  74.  
  75.         commonerror = bigrank = 0;
  76.  
  77.         if ((fp = fopen(indexlist->line, "r")) == NULL) {
  78.             printf("# Name: unknown index\n");
  79.             printf("err: could not open index file\n.\n");
  80.             exit(0);
  81.         }
  82.  
  83.         if (!isokindexheader(fp)) {
  84.             printf("err: the index file format is unknown\n.\n");
  85.             exit(0);
  86.         }
  87.  
  88.         getheader(fp);
  89.  
  90.         if (!getindexfilenum(fp)) {
  91.             printf("err: the index file is empty\n.\n");
  92.             exit(0);
  93.         }
  94.  
  95.         readoffsets(fp);
  96.         readstopwords(fp);
  97.         readfileoffsets(fp);
  98.  
  99.         resultlist = NULL;
  100.         tmplist = searchwordlist;
  101.         tmplist = (struct swline *) fixnot(tmplist, fp);
  102.         searchwordlist = (struct swline *) expandstar(tmplist, fp);
  103.         resultlist = (struct result *) parseterm(fp, 0);
  104.  
  105.         sortresultlist = NULL;
  106.                 while (resultlist != NULL) {
  107.             if (resultlist->structure & structure)
  108.                             sortresultlist = (struct sortresult *)
  109.                             addsortresult(sortresultlist, resultlist->rank,
  110.                             lookupfile(resultlist->filenum, fp));
  111.                         resultlist = resultlist->next;
  112.                 }
  113.  
  114.             fclose(fp);
  115.  
  116.         if (sortresultlist == NULL) {
  117.             if (commonerror)
  118.                 printf("err: a word is too common\n");
  119.             else
  120.                         printf("err: no results\n");
  121.         }
  122.         else {
  123.             if (bigrank)
  124.                 num = 1000.0 / (float) bigrank;
  125.             else
  126.                 num = 1000;
  127.                 printsortedresults(sortresultlist, num);
  128.         }
  129.  
  130.         searchwordlist = tmplist;
  131.         indexlist = indexlist->next;
  132.  
  133.     }
  134.  
  135.         printf(".\n");
  136. }
  137.  
  138. /* This puts parentheses in the right places around not structures
  139. ** so the parser can do its thing correctly.
  140. */
  141.  
  142. struct swline *fixnot(sp)
  143.      struct swline *sp;
  144. {
  145.     int openparen, hasnot;
  146.     char lastline[MAXWORDLEN];
  147.     struct swline *tmpp, *newp;
  148. #ifdef DEBUG
  149.     struct swline *newp2;
  150. #endif
  151.  
  152.     tmpp = sp;
  153.     newp = NULL;
  154.  
  155.     openparen = 0;
  156.     hasnot = 0;
  157.     lastline[0] = '\0';
  158.     while (tmpp != NULL) {
  159.         if ((tmpp->line)[0] == '(')
  160.             openparen++;
  161.         if ((tmpp->line)[0] == ')')
  162.             openparen--;
  163.         if (!strcmp(tmpp->line, "not") && lastline[0] != '\0' &&
  164.         lastline[0] != '(') {
  165.             hasnot = 1;
  166.             newp = (struct swline *) addswline(newp, "(");
  167.         }
  168.         else if (hasnot && !openparen) {
  169.             hasnot = 0;
  170.             newp = (struct swline *) addswline(newp, tmpp->line);
  171.             newp = (struct swline *) addswline(newp, ")");
  172.             strcpy(lastline, tmpp->line);
  173.             tmpp = tmpp->next;
  174.             continue;
  175.         }
  176.         newp = (struct swline *) addswline(newp, tmpp->line);
  177.         strcpy(lastline, tmpp->line);
  178.         tmpp = tmpp->next;
  179.     }
  180.  
  181. #ifdef DEBUG
  182.     newp2 = newp;
  183.     while (newp2 != NULL) {
  184.         printf("%s ", newp2->line);
  185.         newp2 = newp2->next;
  186.     }
  187.     putchar('\n');
  188. #endif
  189.  
  190.     return newp;
  191. }
  192.  
  193. /* Expands words with asterisks as wildcards into a series of
  194. ** "or" searches. Terms like "quick\*" are expanded into
  195. ** "quicktime or quickly", etc.
  196. */
  197.  
  198. struct swline *expandstar(sp, fp)
  199.      struct swline *sp;
  200.      FILE *fp;
  201. {
  202.     int i, firsttime, gotstar;
  203.     char foundword[MAXWORDLEN], searchword[MAXWORDLEN];
  204.         struct swline *newp;
  205.  
  206.     newp = NULL;
  207.     while (sp != NULL) {
  208.         strcpy(searchword, sp->line);
  209.         if (searchword[0] != '*' && strchr(searchword, '*')) {
  210.             for (i = gotstar = 0; searchword[i]; i++)
  211.                 if (gotstar)
  212.                     searchword[i] = '\0';
  213.                 else if (searchword[i] == '*') {
  214.                     searchword[i] = '\0';
  215.                     gotstar = 1;
  216.                 }
  217.             firsttime = 0;
  218.             do {
  219.                 strcpy(foundword, getmatchword(searchword,
  220.                 fp, firsttime));
  221.                 if (strcmp(foundword, NOWORD)) {
  222.                     if (firsttime)
  223.                         newp = (struct swline *)
  224.                         addswline(newp, "or");
  225.                     newp = (struct swline *)
  226.                     addswline(newp, foundword);
  227.                 }
  228.                 else {
  229.                     if (!firsttime)
  230.                         newp = (struct swline *)
  231.                         addswline(newp, NOWORD);
  232.                     break;
  233.                 }
  234.                 firsttime++;
  235.             } while (strcmp(foundword, NOWORD));
  236.         }
  237.         else {
  238.             newp = (struct swline *) addswline(newp,
  239.             searchword);
  240.         }
  241.         sp = sp->next;
  242.     }
  243.     return newp;
  244. }
  245.  
  246. /* If firsttime is 1, returns the first match to a beginnng of a word.
  247. ** Else if it's 0, returns the next match, until nothing is found,
  248. ** in which case NULL is returned.
  249. */
  250.  
  251. char *getmatchword(word, fp, firsttime)
  252.      char *word;
  253.      FILE *fp;
  254.      int firsttime;
  255. {
  256.     int i, c, found;
  257.         char *d;
  258.     static char fileword[MAXWORDLEN];
  259.  
  260.     if (!firsttime) {
  261.         for (i = found = 0; indexchars[i] != '\0'; i++)
  262.             if (word[0] == indexchars[i]) {
  263.                 fseek(fp, offsets[i], 0);
  264.                 found = 1;
  265.             }
  266.         if (!found)
  267.             return NOWORD;
  268.     }
  269.  
  270.     if (offsets[STOPWORDPOS] == ftell(fp))
  271.         return NOWORD;
  272.         for (i = 0; (c = fgetc(fp)) != 0; ) {
  273.                 if (c == ':') {
  274.                         fileword[i] = '\0';
  275.             i = 0;
  276.             while ((c = fgetc(fp)) != 0)
  277.                 ;
  278.             if (fileword[0] != word[0])
  279.                 return NOWORD;
  280.             d = (char *) strstr(fileword, word);
  281.                         if (d != NULL && d == &fileword[0])
  282.                                 return fileword;
  283.             else {
  284.                 if (offsets[STOPWORDPOS] == ftell(fp))
  285.                     return NOWORD;
  286.             }
  287.                 }
  288.         else
  289.             fileword[i++] = c;
  290.     }
  291.     return NOWORD;
  292. }
  293.  
  294. /* Reads and prints the header of an index file.
  295. */
  296.  
  297. void getheader(fp)
  298.      FILE *fp;
  299. {
  300.     int c;
  301.     char line[MAXSTRLEN];
  302.  
  303.     fgets(line, MAXSTRLEN, fp);
  304.         while (1) {
  305.                 c = fgetc(fp);
  306.                 ungetc(c, fp);
  307.                 if (c == '#') {
  308.                         fgets(line, MAXSTRLEN, fp);
  309.                         printf("%s", line);
  310.                         continue;
  311.                 }
  312.         else
  313.             break;
  314.     }
  315.     fseek(fp, 0, 0);
  316. }
  317.  
  318. /* Reads the offsets in the index file so word lookup is faster.
  319. */
  320.  
  321. void readoffsets(fp)
  322.      FILE *fp;
  323. {
  324.     int c, i, k;
  325.     long j, num;
  326.  
  327.     for (i = 0; i < MAXCHARS; i++)
  328.         offsets[i] = 0;
  329.  
  330.     fseek(fp, 0, 0);
  331.     while (1) {
  332.         c = fgetc(fp);
  333.         if (c == '#') {
  334.             do {
  335.                 c = fgetc(fp);
  336.             } while (c && c != '\n');
  337.             continue;
  338.         }
  339.         else
  340.             break;
  341.     }
  342.  
  343.         j = 0;
  344.         while (c != EOF && c != '\n') {
  345.         k = MAXLONGLEN;
  346.                 for (num = 0; c && isdigit(c) && k--; ) {
  347.                         num = (num * 10) + (c - '0');
  348.             c = fgetc(fp);
  349.         }
  350.                 offsets[j++] = num;
  351.         }
  352. }
  353.  
  354. /* Reads the stopwords in the index file.
  355. */
  356.  
  357. void readstopwords(fp)
  358.      FILE *fp;
  359. {
  360.     int i, c;
  361.     char word[MAXWORDLEN];
  362.  
  363.     fseek(fp, offsets[STOPWORDPOS], 0);
  364.     for (i = 0; (c = fgetc(fp)) != '\n' && c != EOF; )
  365.         if (!isspace(c))
  366.             word[i++] = c;
  367.         else {
  368.             word[i] = '\0';
  369.             addstophash(word);
  370.             i = 0;
  371.         }
  372. }
  373.  
  374. /* Reads the file offset table in the index file.
  375. */
  376.  
  377. void readfileoffsets(fp)
  378.      FILE *fp;
  379. {
  380.     int j, k, c;
  381.     long num;
  382.  
  383.         j = 0;
  384.         fseek(fp, offsets[FILEOFFSETPOS], 0);
  385.         c = fgetc(fp);
  386.         while (c != EOF && c != '\n') {
  387.                 k = MAXLONGLEN;
  388.                 for (num = 0; c != EOF && isdigit(c) && k--; ) {
  389.                         num = (num * 10) + (c - '0');
  390.                         c = fgetc(fp);
  391.                 }
  392.                 addtofilehashlist(j++, num);
  393.         }
  394. }
  395.  
  396. /* The recursive parsing function.
  397. ** This was a headache to make but ended up being surprisingly easy. :)
  398. ** parseone tells the function to only operate on one word or term.
  399. */
  400.  
  401. struct result *parseterm(fp, parseone)
  402.      FILE *fp;
  403.      int parseone;
  404. {
  405.     int rulenum;
  406.         char word[MAXWORDLEN];
  407.     struct result *rp, *newrp;
  408.  
  409.     rp = NULL;
  410.  
  411.     rulenum = OR_RULE;
  412.     while (searchwordlist != NULL) {
  413.         strcpy(word, searchwordlist->line);
  414.  
  415.         if (rulenum == NO_RULE)
  416.             rulenum = DEFAULT_RULE;
  417.         if (isunaryrule(word)) {
  418.             searchwordlist = searchwordlist->next;
  419.             rp = (struct result *) parseterm(fp, 1);
  420.             rp = (struct result *) notresultlist(rp, fp);
  421.             continue;
  422.         }
  423.         else if (isbooleanrule(word)) {
  424.             rulenum = getrulenum(word);
  425.             searchwordlist = searchwordlist->next;
  426.             continue;
  427.         }
  428.  
  429.         if (word[0] == '(') {
  430.  
  431.             searchwordlist = searchwordlist->next;
  432.             newrp = (struct result *) parseterm(fp, 0);
  433.  
  434.             if (rulenum == AND_RULE)
  435.                 rp = (struct result *)
  436.                 andresultlists(rp, newrp);
  437.             else if (rulenum == OR_RULE)
  438.                 rp = (struct result *)
  439.                 orresultlists(rp, newrp);
  440.             if (searchwordlist == NULL)
  441.                 break;
  442.  
  443.             continue;
  444.  
  445.         }
  446.         else if (word[0] == ')') {
  447.             searchwordlist = searchwordlist->next;
  448.             break;
  449.         }
  450.  
  451.         rp = (struct result *) operate(rp, rulenum, word, fp);
  452.  
  453.         if (parseone) {
  454.             searchwordlist = searchwordlist->next;
  455.             break;
  456.         }
  457.         rulenum = NO_RULE;
  458.  
  459.         searchwordlist = searchwordlist->next;
  460.         }
  461.  
  462.     return rp;
  463. }
  464.  
  465. /* Looks up a word in the index file -
  466. ** it calls getfileinfo(), which does the real searching.
  467. */
  468.  
  469. struct result *operate(rp, rulenum, word, fp)
  470.      struct result *rp;
  471.      int rulenum;
  472.      char *word;
  473.      FILE *fp;
  474. {
  475.         int i, found;
  476.     struct result *newrp, *returnrp;
  477.  
  478.     if (isstopword(word) && !isrule(word)) {
  479.         if (rulenum == OR_RULE && rp != NULL)
  480.             return rp;
  481.         else
  482.             commonerror = 1;
  483.     }
  484.  
  485.     for (i = found = 0; indexchars[i] != '\0'; i++)
  486.         if (word[0] == indexchars[i]) {
  487.             fseek(fp, offsets[i], 0);
  488.             found = 1;
  489.         }
  490.     if (!found) {
  491.         if (rulenum == AND_RULE)
  492.             return NULL;
  493.         else if (rulenum == OR_RULE)
  494.             return rp;
  495.     }
  496.  
  497.     newrp = (struct result *) getfileinfo(word, fp);
  498.     if (rulenum == AND_RULE)
  499.         returnrp = (struct result *) andresultlists(rp, newrp);
  500.     else if (rulenum == OR_RULE)
  501.         returnrp = (struct result *) orresultlists(rp, newrp);
  502.     else if (rulenum == NOT_RULE)
  503.         returnrp = (struct result *) notresultlist(newrp, fp);
  504.     return returnrp;
  505. }
  506.  
  507. /* Looks up a file name in the index file.
  508. */
  509.  
  510. char *lookupfile(filenum, fp)
  511.      int filenum;
  512.      FILE *fp;
  513. {
  514.         static char line[MAXSTRLEN];
  515.  
  516.         fseek(fp, getfilenum(decodefilenum(filenum) - 1), 0);
  517.         fgets(line, MAXSTRLEN, fp);
  518.  
  519.     return line;
  520. }
  521.  
  522. /* Finds a word and returns its corresponding file and rank information list.
  523. ** If not found, NULL is returned.
  524. */
  525.  
  526. struct result *getfileinfo(word, fp)
  527.      char *word;
  528.      FILE *fp;
  529. {
  530.     int i, c, x, countnum, rank, filenum, structure;
  531.         char fileword[MAXWORDLEN];
  532.         struct result *rp;
  533.  
  534.     rp = NULL;
  535.  
  536.         for (i = 0; (c = fgetc(fp)) != 0; ) {
  537.                 if (c == ':') {
  538.                         fileword[i] = '\0';
  539.             i = 0;
  540.                         if (!strcmp(word, fileword))
  541.                                 break;
  542.                         else {
  543.                 while ((c = fgetc(fp)) != 0)
  544.                     ;
  545.                 if (offsets[STOPWORDPOS] == ftell(fp))
  546.                     return NULL;
  547.                 continue;
  548.             }
  549.                 }
  550.         else
  551.             fileword[i++] = c;
  552.     }
  553.     if (c == 0)
  554.         return NULL;
  555.  
  556.         countnum = 1;
  557.  
  558.     ungetc(c, fp);
  559.     while ((c = fgetc(fp)) != 0) {
  560.         x = 0;
  561.         do {
  562.             c = fgetc(fp);
  563.             if (c == 0)
  564.                 return rp;
  565.             x *= 128;
  566.             x += c & 127;
  567.         } while (c & 128);
  568.         if (x) {
  569.             if (countnum == 1) {
  570.                 filenum = x;
  571.                 countnum++;
  572.             }
  573.             else if (countnum == 2) {
  574.                 rank = x;
  575.                 countnum++;
  576.             }
  577.             else if (countnum == 3) {
  578.                 structure = x;
  579.                 rp = (struct result *)
  580.                 addtoresultlist(rp, filenum, rank,
  581.                 structure);
  582.                 countnum = 1;
  583.             }
  584.         }
  585.     }
  586.  
  587.     return rp;
  588. }
  589.  
  590. /* Is a word a rule?
  591. */
  592.  
  593. int isrule(word)
  594.      char *word;
  595. {
  596.     if (!strcmp(word, "and") || !strcmp(word, "or") || !strcmp(word, "not"))
  597.         return 1;
  598.     else
  599.         return 0;
  600. }
  601.  
  602. /* Is a word a boolean rule?
  603. */
  604.  
  605. int isbooleanrule(word)
  606.      char *word;
  607. {
  608.     if (!strcmp(word, "and") || !strcmp(word, "or"))
  609.         return 1;
  610.     else
  611.         return 0;
  612. }
  613.  
  614. /* Is a word a unary rule?
  615. */
  616.  
  617. int isunaryrule(word)
  618.      char *word;
  619. {
  620.     if (!strcmp(word, "not"))
  621.         return 1;
  622.     else
  623.         return 0;
  624. }
  625.  
  626. /* Return the number for a rule.
  627. */
  628.  
  629. int getrulenum(word)
  630.      char *word;
  631. {
  632.     if (!strcmp(word, "and"))
  633.         return AND_RULE;
  634.     else if (!strcmp(word, "or"))
  635.         return OR_RULE;
  636.     else if (!strcmp(word, "not"))
  637.         return NOT_RULE;
  638.     return NO_RULE;
  639. }
  640.  
  641. /* Takes two lists of results from searches and ANDs them together.
  642. */
  643.  
  644. struct result *andresultlists(r1, r2)
  645.      struct result *r1;
  646.      struct result *r2;
  647. {
  648.         static struct result *tmpnode, *newnode;
  649.  
  650.         if (r1 == NULL || r2 == NULL)
  651.                 return NULL;
  652.  
  653.         newnode = NULL;
  654.  
  655.         while (r1 != NULL) {
  656.                 tmpnode = r2;
  657.                 while (tmpnode != NULL) {
  658.                         if (r1->filenum == tmpnode->filenum)
  659.                                 newnode = (struct result *)
  660.                                 addtoresultlist(newnode, r1->filenum,
  661.                                 (r1->rank + tmpnode->rank) / 2,
  662.                 r1->structure & tmpnode->structure);
  663.                         tmpnode = tmpnode->next;
  664.                 }
  665.                 r1 = r1->next;
  666.         }
  667.  
  668.         return newnode;
  669. }
  670.  
  671. /* Takes two lists of results from searches and ORs them together.
  672. */
  673.  
  674. struct result *orresultlists(r1, r2)
  675.      struct result *r1;
  676.      struct result *r2;
  677. {
  678.         int i;
  679.         struct result *rp;
  680.         static struct result *newnode;
  681.  
  682.     newnode = NULL;
  683.  
  684.         if (r1 == NULL)
  685.                 return r2;
  686.         else if (r2 == NULL)
  687.                 return r1;
  688.  
  689.     initresulthashlist();
  690.     while (r1 != NULL) {
  691.         mergeresulthashlist(r1->filenum, r1->rank, r1->structure);
  692.         r1 = r1->next;
  693.     }
  694.     while (r2 != NULL) {
  695.         mergeresulthashlist(r2->filenum, r2->rank, r2->structure);
  696.         r2 = r2->next;
  697.     }
  698.     for (i = 0; i < HASHSIZE; i++) {
  699.         rp = resulthashlist[i];
  700.         while (rp != NULL) {
  701.             newnode = (struct result *) addtoresultlist(newnode,
  702.             rp->filenum, rp->rank, rp->structure);
  703.             rp = rp->next;
  704.         }
  705.     }
  706.  
  707.         return newnode;
  708. }
  709.  
  710. /* This performs the NOT unary operation on a result list.
  711. ** NOTed files are marked with a default rank of 1000.
  712. */
  713.  
  714. struct result *notresultlist(rp, fp)
  715.      struct result *rp;
  716.      FILE *fp;
  717. {
  718.     int i, filenums;
  719.         struct result *newp;
  720.  
  721.     newp = NULL;
  722.  
  723.     initmarkentrylist();
  724.     while (rp != NULL) {
  725.         marknum(rp->filenum);
  726.         rp = rp->next;
  727.     }
  728.  
  729.     filenums = getindexfilenum(fp);
  730.     for (i = 1; !ismarked(i) && i < filenums; i++)
  731.         newp = (struct result *) addtoresultlist(newp,
  732.         i, 1000, IN_ALL);
  733.  
  734.     return newp;
  735. }
  736.  
  737. /* Adds a file number and rank to a list of results.
  738. */
  739.  
  740. struct result *addtoresultlist(rp, filenum, rank, structure)
  741.      struct result *rp;
  742.      int filenum;
  743.      int rank;
  744.      int structure;
  745. {
  746.         struct result *newnode;
  747.         static struct result *head;
  748.  
  749.         newnode = (struct result *) emalloc(sizeof(struct result));
  750.         newnode->filenum = filenum;
  751.         newnode->rank = rank;
  752.         newnode->structure = structure;
  753.         newnode->next = NULL;
  754.  
  755.         if (rp == NULL)
  756.                 rp = newnode;
  757.         else
  758.                 head->next = newnode;
  759.  
  760.         head = newnode;
  761.  
  762.         return rp;
  763. }
  764.  
  765. /* Adds the results of a search, sorts them by rank.
  766. */
  767.  
  768. struct sortresult *addsortresult(sp, rank, fileinfo)
  769.      struct sortresult *sp;
  770.      int rank;
  771.      char *fileinfo;
  772. {
  773.         if (rank > bigrank)
  774.                 bigrank = rank;
  775.  
  776.         if (sp == NULL) {
  777.                 sp = (struct sortresult *) emalloc(sizeof(struct sortresult));
  778.                 sp->rank = rank;
  779.                 sp->fileinfo = (char *) mystrdup(fileinfo);
  780.                 sp->left = sp->right = NULL;
  781.         }
  782.         else {
  783.                 if (sp->rank < rank)
  784.                         sp->left = (struct sortresult *)
  785.                         addsortresult(sp->left, rank, fileinfo);
  786.                 else
  787.                         sp->right = (struct sortresult *)
  788.                         addsortresult(sp->right, rank, fileinfo);
  789.         }
  790.  
  791.         return sp;
  792. }
  793.  
  794. /* Prints the final results of a search.
  795. */
  796.  
  797. void printsortedresults(sp, num)
  798.      struct sortresult *sp;
  799.      float num;
  800. {
  801.         int rank;
  802.  
  803.         if (sp != NULL) {
  804.                 printsortedresults(sp->left, num);
  805.                 rank = (int) ((float) sp->rank * num);
  806.                 if (rank >= 999)
  807.                         rank = 1000;
  808.         if (maxhits) {
  809.                     if (maxhits == -1)
  810.                 printf("%d %s", (rank <= 0) ? 1 :
  811.                 rank, sp->fileinfo);
  812.             else if (maxhits > 0) {
  813.                 printf("%d %s", (rank <= 0) ? 1 :
  814.                 rank, sp->fileinfo);
  815.                 maxhits--;
  816.             }
  817.         }
  818.                 printsortedresults(sp->right, num);
  819.         }
  820. }
  821.  
  822. /* Reads a compressed line. This is just here for testing, etc.
  823. */
  824.  
  825. void getrawindexline(fp)
  826.      FILE *fp;
  827. {
  828.         int c, inword;
  829.  
  830.         inword = 1;
  831.         while ((c = fgetc(fp)) != EOF) {
  832.                 if (c == ':' && inword)
  833.                         inword = 0;
  834.                 if (!inword) {
  835.                         do {
  836.                                 c = fgetc(fp);
  837.                                 if (c == 0)
  838.                                         return;
  839.                         } while (c & 128);
  840.                 }
  841.         }
  842. }
  843.  
  844. /* Does an index file have a readable format?
  845. */
  846.  
  847. int isokindexheader(fp)
  848.      FILE *fp;
  849. {
  850.     char line[MAXSTRLEN];
  851.  
  852.     fseek(fp, 0, 0);
  853.     fgets(line, MAXSTRLEN, fp);
  854.     if (line[strlen(line) - 1] == '\n')
  855.         line[strlen(line) - 1] = '\0';
  856.     if (strcmp(line, INDEXHEADER)) {
  857.         fseek(fp, 0, 0);
  858.         return 0;
  859.     }
  860.     fseek(fp, 0, 0);
  861.     return 1;
  862. }
  863.